package com.heima.media.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.dto.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.minio.MinIOService;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.media.dto.ArticleDto;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.entity.WmChannel;
import com.heima.media.entity.WmNews;
import com.heima.media.entity.WmSensitive;
import com.heima.media.entity.WmUser;
import com.heima.media.feign.ArticleClient;
import com.heima.media.service.*;
import org.apache.commons.io.IOUtils;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Service
public class IAuditServiceImpl implements IAuditService {

    @Autowired
    private GreenImageScan imageScan;

    @Autowired
    private GreenTextScan textScan;

    @Autowired
    private IWmNewsService newsService;

    @Autowired
    private MinIOService minIOService;

    @Autowired
    private ArticleClient articleClient;

    @Autowired
    private IWmUserService userService;

    @Autowired
    private IWmChannelService channelService;

    @Autowired
    private IWmSensitiveService sensitiveService;

    @Async  //当前方法需要使用线程
    @Override
    public void audit(WmNews wmNews) {
        System.out.println(Thread.currentThread().getName() + "开始执行审核");
        //判断当前文章的状态
        //8 到达了发布时间开始发布审核
        if (wmNews.getStatus() == 8){
            publishArticle(wmNews);
        }
        //如果状态是1 自动审核
        //提取内容中的文本和图片
        Map<String, Object> map = getTextAndImageFormContent(wmNews.getContent());
        //获取文本内容
        String text = (String) map.get("text");
        //获取图片内容
        List<String> image = (List<String>) map.get("image");

        //自管理敏感词审核
        boolean selfResult = checkSelf(wmNews, text);
        if (!selfResult) return;

        //调用阿里云文本审核
        boolean textResult = checkText(wmNews, text);
        if (!textResult) return;

        //调用阿里云图片审核
        boolean imageResult = checkImage(wmNews, image);
        if (!imageResult) return;
        //调用文章服务保存
        //如果没有到发布时间，将文章状态改为8，审核通过待发布，发送延迟任务
        sendDelayMessage(wmNews);

        publishArticle(wmNews);
        System.out.println(Thread.currentThread().getName() + "审核完成");
    }
    @Autowired
    private RedissonClient redissonClient;
    /**
     * 发送延迟消息
     * @param wmNews
     */
    private void sendDelayMessage(WmNews wmNews) {
        if (wmNews.getPublishTime().getTime()>System.currentTimeMillis()) {
            wmNews.setStatus(8);
            newsService.updateById(wmNews);
            RBlockingQueue<String> blockingQueue = redissonClient.getBlockingQueue("article_publish");

            // 开启监听时发送一条初始化消息
            // 创建延迟队列
            RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
            //延迟的时间为
            Long time=wmNews.getPublishTime().getTime()-System.currentTimeMillis();
            delayedQueue.offer(JSON.toJSONString(wmNews), time, TimeUnit.MICROSECONDS);
            System.out.println("消息发送完成"+new Date());
        }
    }

    /**
     * 自管理敏感词
     *
     * @param wmNews
     * @param text
     * @return
     */
    private boolean checkSelf(WmNews wmNews, String text) {
        //第一次使用时将数据库中的敏感词查询出来进行map初始化
        if (SensitiveWordUtil.dictionaryMap.size() == 0) {
            //从数据库查询
            //select sensitives from wm_sensitive
            LambdaQueryWrapper<WmSensitive> query = new LambdaQueryWrapper<>();
            //选择一列sensitives
            query.select(WmSensitive::getSensitives);
            List<String> works = sensitiveService.listObjs(query, new Function<Object, String>() {
                @Override
                public String apply(Object o) {
                    return o.toString();
                }
            });
            //初始化map
            SensitiveWordUtil.initMap(works);
        }
        // 匹配拼接文本，标题，正文文字的内容
        String content = wmNews.getTitle() + wmNews.getLabels() + text;
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        //判断结果 map大于0.审核失败
        if (map.size() > 0) {
            //违规 ，修改文章状态为审核失败 记录失败原因
            wmNews.setStatus(2);
            //获取所有的key敏感词
            Set<String> keys = map.keySet();
            //多个字符串用，分开的一个字符串String.join(",", keys);
            String label = String.join(",", keys);
            wmNews.setReason("阿里云文本审核失败" + label);
            //更新新闻表状态
            newsService.updateById(wmNews);
            return false;
        }else {
            return true;
        }
    }

    /**
     * 发布文章
     *
     * @param wmNews
     */
    private void publishArticle(WmNews wmNews) {
        ArticleDto dto = new ArticleDto();
        //设置文章数据
        BeanUtils.copyProperties(wmNews, dto);
        dto.setId(null);
        //获取作者id
        WmUser wmUser = userService.getById(wmNews.getUserId());
        //查询作者信息
        dto.setAuthorName(wmUser.getName());
        //查询频道信息
        WmChannel wmChannel = channelService.getById(wmNews.getChannelId());
        dto.setChannelName(wmChannel.getName());
        dto.setLayout(wmNews.getType());
        dto.setFlag(0);
        //封面图片需要转换
        List<ImageDto> coverImages = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        List<String> list = new ArrayList<>();
        for (ImageDto coverImage : coverImages) {
            list.add(coverImage.getUrl());
        }
        //将集合转换成逗号分割的字符串
        String join = String.join(",", list);
        dto.setImages(join);
        //远程调用
        ResponseResult<Long> responseResult = articleClient.saveArticle(dto);
        //判断结果
        if (responseResult.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())) {
            Long articleId = responseResult.getData();
            //将文章id写回到自媒体文章表中，并且修改状态改为9
            wmNews.setArticleId(articleId);
            wmNews.setStatus(9);
            newsService.updateById(wmNews);
        }
    }

    /**
     * 阿里云审核图片
     *
     * @param wmNews
     * @param image
     * @return
     */
    private boolean checkImage(WmNews wmNews, List<String> image) {
        //需要审核的图片 包含内容封面
        List<ImageDto> list = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        //遍历
        for (ImageDto imageDto : list) {
            //判断封面是否存在内容图片中
            if (!image.contains(imageDto.getUrl())) {
                //判断封面图片是否为空
                if (!StringUtils.isEmpty(imageDto.getUrl())) {
                    //将封面图片加入到最终要审核的图片集合中
                    image.add(imageDto.getUrl());
                }
            }
        }
        //判断图片集合是否有图片
        if (image.size() == 0) {
            return true;
        }
        //下载图片
        //因为minio没有外网地址所以先下载
        boolean result = false;
        try {
            List<byte[]> imageList = new ArrayList<>();
            //遍历图片集合到minio中下载
            for (String s : image) {
                InputStream inputStream = minIOService.download(s);
                //将InputStream 转换成字节数组
                byte[] bytes = IOUtils.toByteArray(inputStream);
                imageList.add(bytes);
            }
            Map map = imageScan.imageScan(imageList);
            //分析结果
            //suggestion 的结果
            String suggestion = (String) map.get("suggestion");
            //pass结果正常，block结果违规，review需要人工审核
            switch (suggestion) {
                case "pass":
                    //正常
                    result = true;
                    break;
                case "block":
                    //违规 ，修改文章状态为审核失败 记录失败原因
                    wmNews.setStatus(2);
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云文本审核失败" + label);
                    //更新状态
                    newsService.updateById(wmNews);
                    break;
                case "review":
                    //人工审核 ，改状态为3
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 阿里云审核文本
     *
     * @param wmNews
     * @param text
     * @return
     */
    private boolean checkText(WmNews wmNews, String text) {
        boolean result = false;
        // 文本，标题，正文文字
        String content = wmNews.getTitle() + wmNews.getLabels() + text;
        try {
            Map map = textScan.greenTextScan(content);
            //分析结果
            //suggestion 的结果
            String suggestion = (String) map.get("suggestion");
            //pass结果正常，block结果违规，review需要人工审核
            switch (suggestion) {
                case "pass":
                    //正常
                    result = true;
                    break;
                case "block":
                    //违规 ，修改文章状态为审核失败 记录失败原因
                    wmNews.setStatus(2);
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云文本审核失败" + label);
                    //更新状态
                    newsService.updateById(wmNews);
                    break;
                case "review":
                    //人工审核 ，改状态为3
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 提取内容中的文本和图片
     *
     * @param content
     * @return
     */
    private Map<String, Object> getTextAndImageFormContent(String content) {
        //将内容转换成ContentDto 集合
        List<ContentDto> contentDtos = JSON.parseArray(content, ContentDto.class);
        //定义返回结果
        Map<String, Object> map = new HashMap<>();
        //定义文本内容
        StringBuilder sb = new StringBuilder();
        //定义图片集合
        List<String> images = new ArrayList<>();
        //遍历
        for (ContentDto contentDto : contentDtos) {
            if (contentDto.getType().equals("text")) {
                sb.append(contentDto.getValue());
            } else {
                images.add(contentDto.getValue());
            }
        }
        map.put("text", sb.toString());
        map.put("image", images);
        return map;
    }
}
